package netty.dubboRPC.netty;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.util.concurrent.Callable;

/**
 * @ClassName NettyClientHandler
 * @Description TODO
 * @Author director吴
 * @Date 2022/5/18 14:21
 * @Version 1.0
 **/
public class NettyClientHandler extends ChannelInboundHandlerAdapter implements Callable {


    private ChannelHandlerContext context;//上下文
    private String result;//返回结果
    private String para; //客户端调用方法时，传入的参数.需要发送的数据





    //(1)
    //连接创建成功就被调用
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {

        context = ctx; //其他方法会用到这个上下文

    }

    //(2)
    //传入需要发送的数据
    public void setPara(String para){
        this.para = para;
    }



    //(3) --> 执行发送数据的逻辑，顺序卡在 wait()
    /**
     *被代理对象调用，然后发送数据给服务端。发送完毕之后进入等待状态wait()
     */
    @Override
    public synchronized Object call() throws Exception {

        context.writeAndFlush(para);
        wait();
        return result;
    }

    //(4) --> 接收服务端的回调，执行完毕后释放线程，回到(3)中执行wait()后的代码
    //收到服务器数据后被调用
    @Override
    public synchronized void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        result = msg.toString();
        /**
         * 原因：关于为什么要使用线程唤醒
         * -->  netty在做远程调用的时候,客户端将数据发送给服务端时候,需要同步接收数据。也就是说,在客户端发送数据,
         *      服务端返回结果,但是客户端未收到的这段时间内，发送完数据的那个线程一直处于等待状态，调用了wait()。
         *      而返回的数据和发送的数据等待的线程，是在两个地方。所以需要同步一下
         */
        notify();//唤醒等待的线程
    }





    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}
